#include <string>
#include <iostream>
using namespace std;
#include "mem/mo_hash.h"
#include "mem/new_allocator.h"
using namespace tdl;

struct uinfo
{
	uint	cip;
	char	lc[16];
public:
	uinfo(uint ip, const char* s, size_t slen) : cip(ip)
	{
		memset(lc, 0, 16);
		memcpy(lc, s, slen);
	}
	uinfo(const uinfo& ui)
	{
		cip = ui.cip;
		memcpy(lc, ui.lc, 16);
	}
	friend inline ostream& operator<<(ostream& os, const uinfo& ui)
	{
		os << "(" << ui.cip << "," << ui.lc << ")";
		return os;
	}
};

// customed struct as key
struct vkey
{
	int		cip;
	char	s[8];
public:
	vkey() : cip(0) { memset(s, 0, 8); }
	vkey(int xx, string& ss) : cip(xx) { memset(s, 0, 8); memcpy(s, ss.c_str(), ss.length()); }
	vkey(const vkey& v) { cip = v.cip; memcpy(s, v.s, 8); }
	void operator=(const vkey& vk) { cip = vk.cip; memcpy(s, vk.s, 8); }

	vkey operator+(int i) { string ss = string(s); return vkey(cip + i, ss); }
	friend inline ostream& operator<<(ostream& os, const vkey& k)
	{
		os << "(" << k.cip << "," << k.s << ")";
		return os;
	}
};
//inline bool operator<(const vkey& vk1, const vkey& vk2) { return vk1.x < vk2.x; }
inline bool operator==(const vkey& vk1, const vkey& vk2) { return vk1.cip == vk2.cip; }
template <typename T> struct my_hash;
template <> struct my_hash<vkey>
{
	size_t operator()(const vkey& vk, size_t h = DEFAULT_HASH) const
	{ return vk.cip % h; }
};

///////////////////////////
uint moh_node_num = 1000;
key_t shm_key = 0x5081524;

template <typename T, typename Tkey, typename Tvalue>
bool test_moh(T& moh, Tkey& key, Tvalue value)
{
	typedef typename T::dn_type dn_type;
	typedef typename T::pair_type pair_type;
	typedef typename T::iterator iterator;

	pair_type pair;

	try {
		if(moh.initialize(moh_node_num, shm_key++))
		{
			cout << "total elements=" << moh.get_total_elm() << endl;
			pair = moh.get(3);
			if(pair.second)
				cout << "get(3)=" << pair.first->value() << endl;
			else
				cout << "get(3)=" << false << endl;
			return false;
		}

		bool r = moh.insert(key, &value);
		cout << "insert(1, 11)=" << r << endl;
		r = moh.insert(key, &value);
		cout << "insert(1, 11)=" << r << endl;

		pair = moh.find(key + 3);
		cout << "find(4)=" << pair.second << endl;

		pair = moh.find(key);
		dn_type* pdn = pair.first;
		pdn->value().cip++;
		moh.touch(pdn);
		pair = moh.find(key);
		cout << "after modify, find(1)=" << pair.first->value() << endl;

		r = moh.erase(key);
		cout << "erase(1)=" << r << endl;

		value.cip += 1;
		r = moh.insert(key + 1, &value);
		cout << "insert(2, 12)=" << r << endl;
		sleep(1);
		value.cip += 1;
		r = moh.insert(key + 2, &value);
		cout << "insert(3, 13)=" << r << endl;
		sleep(1);
		value.cip += 1;
		r = moh.insert(key + 3, &value);
		cout << "insert(4, 14)=" << r << endl;
		sleep(1);

		pair = moh.get(key + 1);
		cout << "get(2)=" << pair.second << endl;
		sleep(1);

		moh.touch(key + 2);
		cout << "touch(3)" << endl;
		sleep(1);

		cout << "iterate in moh: " << endl;
		for(iterator it = moh.begin(); it != moh.end(); ++it)
			cout << "key=" << it->key() << ", value=" << it->value() << endl;

		return true;
	} catch(mohash_ex& e) { cerr << e.what() << endl; return false; }
}

template <typename T>
uint recycle_moh(T& moh, unsigned long cond, ostringstream& oss)
{
	typename T::rcc_type rcc;
	uint n = moh.recycle(&cond, &rcc);
	for(typename T::rcc_type::iterator it = rcc.begin(); it != rcc.end(); ++it)
		oss << "	key=" << it->key() << ", value=" << it->value() << endl;
	return n;
}

template <typename T, typename Tkey>
bool test_moh_onlykey(T& moh, Tkey& key)
{
	typedef typename T::dn_type dn_type;
	typedef typename T::pair_type pair_type;
	typedef typename T::iterator iterator;

	pair_type pair;

	try {
		if(moh.initialize(moh_node_num, shm_key++))
		{
			cout << "total elements=" << moh.get_total_elm() << endl;
			string s = "tommy";
			Tkey k(3, s);
			pair = moh.get(k);
			if(pair.second)
				cout << "get(3)=" << pair.first->key() << endl;
			else
				cout << "get(3)=" << false << endl;
			return false;
		}

		bool r = moh.insert(key);
		cout << "insert(1)=" << r << endl;
		r = moh.insert(key);
		cout << "insert(1)=" << r << endl;

		pair = moh.find(key + 3);
		cout << "find(4)=" << pair.second << endl;

		r = moh.erase(key);
		cout << "erase(1)=" << r << endl;

		r = moh.insert(key + 1);
		cout << "insert(2)=" << r << endl;
		sleep(1);
		r = moh.insert(key + 2);
		cout << "insert(3)=" << r << endl;
		sleep(1);
		r = moh.insert(key + 3);
		cout << "insert(4)=" << r << endl;
		sleep(1);

		pair = moh.get(key + 1);
		cout << "get(2)=" << pair.second << endl;
		sleep(1);

		moh.touch(key + 2);
		cout << "touch(3)" << endl;
		sleep(1);

		cout << "iterate in moh: " << endl;
		for(iterator it = moh.begin(); it != moh.end(); ++it)
			cout << "key=" << it->key() << endl;

		return true;
	} catch(mohash_ex& e) { cerr << e.what() << endl; return false; }
}

template <typename T>
uint recycle_moh_onlykey(T& moh, unsigned long cond, ostringstream& oss)
{
	typename T::rcc_type rcc;
	uint n = moh.recycle(&cond, &rcc);
	for(typename T::rcc_type::iterator it = rcc.begin(); it != rcc.end(); ++it)
		oss << "	key=" << it->key() << endl;
	return n;
}
/////////////////////
typedef tdl::mo_hash<uint, uinfo, 16, tdl::hash, mohash_sp::accesstime_sort_policy> moh1;
typedef tdl::mo_hash<uint, uinfo, 32, tdl::hash, mohash_sp::createtime_sort_policy> moh2;
typedef tdl::mo_hash<uint, uinfo, 16, tdl::hash, mohash_sp::usecount_sort_policy> moh3;
typedef tdl::mo_hash<uint, uinfo> moh4;
typedef tdl::mo_hash<string, uinfo> mohhh;

typedef tdl::mo_hash_onlykey<vkey, 50, my_hash, mohash_sp::accesstime_sort_policy> moh5;
typedef tdl::mo_hash_onlykey<vkey, 16, my_hash, mohash_sp::createtime_sort_policy> moh6;
typedef tdl::mo_hash_onlykey<vkey, 32, my_hash, mohash_sp::usecount_sort_policy> moh7;
typedef tdl::mo_hash_onlykey<vkey, 48, my_hash> moh8;
				
//////////////////////
int main(int argc, char* argv[])
{
	string s = "tommy";
	uinfo ui(11, s.c_str(), s.length());
	uint n, simple_key = 1;
	vkey var_key(1, s);
	ostringstream oss;
	time_t timeout_time;
	unsigned long use_cnt_cond = 2;

	moh1 m1;
	cout << "********************" << endl << "sizeof(moh1.data_node)=" << sizeof(moh1::dn_type) << endl;
	if(test_moh(m1, simple_key, ui))
	{
		timeout_time = ::time(0) - 2;
		n = recycle_moh(m1, timeout_time, oss);
		cout << "recycle(now-2)=" << n << endl << oss.str();
		cout << "elements left=" << m1.get_total_elm() << endl;
		oss.str("");
	}

	moh2 m2;
	cout << "********************" << endl << "sizeof(moh2.data_node)=" << sizeof(moh2::dn_type) << endl;
	if(test_moh(m2, simple_key, ui))
	{
		timeout_time = ::time(0) - 2;
		n = recycle_moh(m2, timeout_time, oss);
		cout << "recycle(now-2)=" << n << endl << oss.str();
		cout << "elements left=" << m2.get_total_elm() << endl;
		oss.str("");
	}

	moh3 m3;
	cout << "********************" << endl << "sizeof(moh3.data_node)=" << sizeof(moh3::dn_type) << endl;
	if(test_moh(m3, simple_key, ui))
	{
		n = recycle_moh(m3, use_cnt_cond, oss);
		cout << "recycle(uc<2)=" << n << endl << oss.str();
		cout << "elements left=" << m3.get_total_elm() << endl;
		oss.str("");
	}
			 																																						
	moh4 m4;
	cout << "********************" << endl << "sizeof(moh4.data_node)=" << sizeof(moh4::dn_type) << endl;
	test_moh(m4, simple_key, ui);
	cout << "elements left=" << m4.get_total_elm() << endl;

	moh5 m5;
	cout << "********************" << endl << "sizeof(moh5.data_node)=" << sizeof(moh5::dn_type) << endl;
	test_moh_onlykey(m5, var_key);
	timeout_time = ::time(0) - 2;
	n = recycle_moh_onlykey(m5, timeout_time, oss);
	cout << "recycle(now-2)=" << n << endl << oss.str();
	cout << "elements left=" << m5.get_total_elm() << endl;
	oss.str("");

	moh6 m6;
	cout << "********************" << endl << "sizeof(moh6.data_node)=" << sizeof(moh6::dn_type) << endl;
	test_moh_onlykey(m6, var_key);
	timeout_time = ::time(0) - 2;
	n = recycle_moh_onlykey(m6, timeout_time, oss);
	cout << "recycle(now-2)=" << n << endl << oss.str();
	cout << "elements left=" << m6.get_total_elm() << endl;
	oss.str("");
	
	moh7 m7;
	cout << "********************" << endl << "sizeof(moh7.data_node)=" << sizeof(moh7::dn_type) << endl;
	test_moh_onlykey(m7, var_key);
	use_cnt_cond = 2;
	n = recycle_moh_onlykey(m7, use_cnt_cond, oss);
	cout << "recycle(uc<2)=" << n << endl << oss.str();
	cout << "elements left=" << m7.get_total_elm() << endl;
	oss.str("");
				 																																						
	moh8 m8;
	cout << "********************" << endl << "sizeof(moh8.data_node)=" << sizeof(moh8::dn_type) << endl;
	test_moh_onlykey(m8, var_key);
	cout << "elements left=" << m8.get_total_elm() << endl;

//	m1.clear(); m2.clear(); m3.clear(); m4.clear();
//	m5.clear(); m6.clear(); m7.clear(); m8.clear();

	return 0;
}

